{"id":13484261,"url":"https://github.com/play/play","last_synced_at":"2025-12-16T18:13:03.950Z","repository":{"id":47899239,"uuid":"1539787","full_name":"play/play","owner":"play","description":"play ► — your company's dj","archived":false,"fork":false,"pushed_at":"2017-04-06T02:42:46.000Z","size":6817,"stargazers_count":2703,"open_issues_count":35,"forks_count":366,"subscribers_count":112,"default_branch":"master","last_synced_at":"2025-02-15T17:17:01.419Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://zachholman.com/screencast/play/","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/play.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2011-03-29T03:29:10.000Z","updated_at":"2025-02-15T13:54:10.000Z","dependencies_parsed_at":"2022-08-14T00:30:26.613Z","dependency_job_id":null,"html_url":"https://github.com/play/play","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/play%2Fplay","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/play%2Fplay/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/play%2Fplay/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/play%2Fplay/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/play","download_url":"https://codeload.github.com/play/play/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240222328,"owners_count":19767458,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T17:01:21.498Z","updated_at":"2025-12-16T18:12:58.877Z","avatar_url":"https://github.com/play.png","language":"Ruby","readme":"# Play\n\nPlay is an employee-powered iTunes-based client-driven distributed music server\nfor your office. Also it can prepare your taxes.\n\n## Background\n\nDid you know that listening to music while you work produces better and faster\ncode? It's true. It's in a README.\n\nWe listen to music constantly at GitHub. So I wrote Play. Initially it was a\nmodest shell-oriented music server, but we've since grown it to quite the setup:\n\n![Play at GitHub](http://cl.ly/1l3o0p0K3O1r0C2U3a3Z/play.png)\n\nWe have employees all over the world, but Play lets us all listen to the same\nmusic as if we were all in the office together. This has actually made a big\nimpact on our culture.\n\n## The Setup\n\n### OS X\n\nPlay is built for the Mac. We use a Mac Mini.\n\n### iTunes\n\nPlay is **iTunes-based**. That means we can let iTunes do what it's good at and\nmanage the state of our music. We use **iTunes DJ** to handle the main Play\nqueue, specifically because it emulates what Play does: provide a smart playlist of\nneverending songs.\n\n### The Stream and Speakers\n\nWe use [Nicecast][nicecast] to take the audio stream from iTunes and deliver it\nto our client apps so everyone can stream from their platform of choice.\n\nWe also use iTunes' built-in AirPlay support to stream to multiple speakers\nacross our office network.\n\n### Web\n\nThe heart of Play is the web app. This is effectively an API to access and\ncontrol your iTunes library over the web. The app also handles music upload:\njust drag your files to the browser window, then they'll get uploaded and\nindexed in iTunes. No complex file sharing and office VPN setups necessary.\n\n### Pusher\n\nPlay's realtime notification is powered by [Pusher](http://pusher.com/). Pusher\nallows Play to provide realtime updating to any client that cares. This includes\nthe site as well as Play clients. Clients will be updated in realtime as Play cycles\nthrough songs as well as when new songs get queued.\n\n### API\n\nWe primarily drive Play through [Campfire][campfire], the chat service we use\ninternally at GitHub. Most Play interactions happen through the API rather than\nthe web interface, and the API is actually a superset of the functionality\navailable through the web.\n\n## Installation\n\n### Setup\n\nPlay has a lot of moving parts, but we've tried to simplify installation as much\nas we could.\n\nFirst, clone down the repository:\n\n    git clone https://github.com/play/play.git \u0026\u0026 cd play\n\nNext, you need to run the bootstrap process, which will verify that we can talk\nto iTunes, that you have all of your settings set up correctly, and will guide\nyou through the configuration setup:\n\n    script/bootstrap\n\nDuring the bootstrap process you'll be asked to enter your [Pusher][pusher]\ncredentials. This is optional, but it'll let you get realtime updates to your\nPlay queue. It's like the future. Websockets and shit.\n\n### Starting It Up\n\nOpen up iTunes and start playing music from the iTunes DJ playlist. It's important that you **do this first**. **Yes** the DJ playlist is required.\n\n**iTunes Match is mostly NOT supported. See more details on this at the bottom of this README.**\n\nAt this point, you should be ready to play:\n\n    rake start\n\nThat'll start the server up on [localhost:5050](http://localhost:5050).\n\n### Hubot Integration\n\nWe use Play primarily through Campfire, through Hubot. There's a\n[play.coffee](https://github.com/github/hubot-scripts/blob/master/src/scripts/play.coffee)\nfile that you can drop into your Hubot installation for integration with Play.\n\n### API/Client Auth\n\nEach user on Play has a unique auth `token`. They will give this `token` to each Play client for it to make requests on their behalf.\n\nIn addition to these unique tokens, each Play installation also has its own unique system wide auth `token`. This can be used to auth and masquerade as any user on the system. When using this system wide `token`, a `login` must be provided in the request so Play knows what user the request is masquerading as. This is essentially how [Hubot](https://github.com/github/hubot) will communicate with Play.\n\nBoth of these styles tokens can be included as a **header** or as a **query param**.\n\n### User Token\n\nWhen using a user's `token`, only the `token` needs to be included. It can be added to the request in the header or as a query param.\n\n#### Header\n\n    \"Authorization: 5422fd\"\n\n#### Query Param\n\n    ?token=5422fd\n\n### System Token\n\nWhen using a system token, a `login` needs to be added to the request in addition to the system `token` added by the means described above. It can be added to the request in the header or as a query param.\n\n#### Header\n\n    \"X-PLAY-LOGIN: maddox\"\n\n#### Query Param\n\n    ?login=maddox\n\n\n### Clients\n\nPart of the fun with Play is getting it everywhere: in your office, on your\ndesktop, and on your phone. Once you get Play set up correctly, you'll need to\ninstall [Nicecast][nicecast].\n\nThe following clients exist for Play:\n\n#### OS X\n\n[play/play-cocoa](https://github.com/play/play-cocoa)\n\n\u003ca href=\"https://github.com/play/play-cocoa\"\u003e![](http://f.cl.ly/items/3J2U1Z2x033R3p1I1J0b/play-item.png)\u003c/a\u003e\n\n#### iOS\n\n[play/play-cocoa](https://github.com/play/play-cocoa)\n\n\u003ca href=\"https://github.com/play/play-cocoa\"\u003e![](http://f.cl.ly/items/1Z1W3P351q2V1m2v3n12/play-ios-iphone.png)\u003c/a\u003e\n\u003ca href=\"https://github.com/play/play-cocoa\"\u003e![](http://f.cl.ly/items/2Z0O09320f142y3x163q/play-ios-ipad.png)\u003c/a\u003e\n\n#### Windows\n\n[play/play-windows](https://github.com/play/play-windows)\n\n\u003ca href=\"https://github.com/play/play-windows\"\u003e![](http://cl.ly/3D0u3N102O1D0m1g3B1Y/Image%202012.04.19%202:35:54%20AM.png)\u003c/a\u003e\n\n\n#### Android\n\n[play/play-android](https://github.com/play/play-android)\n\n\u003ca href=\"https://github.com/play/play-android\"\u003e![](http://f.cl.ly/items/2S3c2s2K0Y1h1W1F0L0H/android-screenshot.png)\u003c/a\u003e\n\n#### Now Playing on TV\n\nWe also have a TV at the office with the currently-playing song. This doesn't\nrequire any setup; just point your TV's browser at the main Play instance and\nthe TV interface should show up as long as the screen ratio is 16:9\n(ie, 720p or 1080p).\n\n![](http://cl.ly/1c0D0d0Y1a1K0S3s0N0m/Image%202012.04.19%204:46:51%20PM.png)\n\n## Technical Details\n\n### AppleScript\n\nThe entire Play + iTunes bridge is handled via AppleScript. Play talks to\nAppleScript, AppleScript talks to iTunes, and we make it dance.\n\n### The Web is the API\n\nThe web app is a simple, straightfoward Sinatra app. State that we can't stash\nin iTunes is persisted through **Redis**.\n\nThe entire web app is just a thin client over the API, which is delivered\nthrough JSON. We only really deliver one HTML page: the main root page. All data\non that page is populated via JSON requests. This means we can focus on one API\nand use it for both the web and for every other client.\n\nThe frontend is built with SCSS, CoffeeScript, Mustache, Pusher, and jQuery. All\nassets are compiled and delivered via Sprockets.\n\n### Native Clients\n\nNative clients use [Pusher](http://pusher.com/) to be updated in realtime. They will show\nwhat is currently playing, and with some clients, what is queued. All clients are built\nto consume the Shoutcast stream.\n\n## iTunes Match\n\nLike many people have experienced with iOS apps that use your music library, iTunes Match royally\nscrews this up. iTunes does nothing to differentiate songs that are actually available on disk, and those\nthat would need to be pulled down first by Match in order to play them.\n\nThis screws up Play, just as it screws up iOS apps that naively (not their fault) attempt to play something\nout of the music library that is actually only available via Match.\n\nThis can hopefully be addressed in the future. For now, skip Match.\n\n## Contributing\n\nWe'd love to see your contributions to Play. If you'd like to hack on Play,\nyou'll likely want to run Play in development mode:\n\n    shotgun\n\nThat will reload the code on each page request. You can hit the server on\n[localhost:9393](http://localhost:9393).\n\nYou can run the tests with:\n\n    rake\n\nFork the project, make your commits, then send a Pull Request.\n\n## Play\n\nPlay was written by [Zach Holman](https://twitter.com/holman) and shaped by the\nfine ladies and gentlemen at [GitHub](https://github.com/github). We've also\nbenefited from a lot of hard work from our\n[contributors](https://github.com/play/play/contributors).\n\n[nicecast]: http://rogueamoeba.com/nicecast/\n[campfire]: http://campfirenow.com/\n[pusher]:   http://pusher.com/\n","funding_links":[],"categories":["Ruby","Misc","Music and Sound"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fplay%2Fplay","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fplay%2Fplay","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fplay%2Fplay/lists"}